<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        box-sizing: border-box;
      }
      body {
        margin: 0;
      }
      h1 {
        text-align: center;
      }
      .main {
        position: relative;
      }
      .item {
        position: absolute;
        color: #fff;
        display: flex;
        justify-content: center;
        align-items: center;
        transition: left 0.3s, top 0.3s, transform 0.3s;
      }
      .item:after {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        transition: background-color 0.2s;
      }
      .item.disabled:after {
        background-color: rgba(0, 0, 0, 0.5);
      }
      .move_list {
        border: 1px solid #ddd;
        background-color: #ddd;
        margin: 0 auto;
      }
    </style>
  </head>
  <body>
    <h1>汪了个汪</h1>
    <div class="main"></div>
    <div class="move_list"></div>
    <script>
      // 基础数据
      const simpleData = [
        { name: "虎", color: "#ff1100" },
        { name: "兔", color: "#ff8800" },
        { name: "牛", color: "green" },
        { name: "羊", color: "#779922" },
        { name: "蛇", color: "blue" },
        { name: "鼠", color: "#335577" },
      ];
      // 卡片大小
      const size = 50;
      // 行
      const rows = 10;
      // 列
      const cols = 10;
      // 3个一清楚
      const oneGroupCount = 3;
      // 每个消除有6组
      const group = 6;
      // 总共6层
      const layerCount = 6;
      const cellHtml = [];

      const renderData = Array.from(new Array(oneGroupCount * group))
        .map((v) => {
          return simpleData.map((v) => ({ ...v }));
        })
        .flat()
        .sort((v) => Math.random() - 0.5);

      for (let ly = layerCount - 1; ly >= 0; ly--) {
        for (let i = 0; i < rows; i++) {
          for (let j = 0; j < cols; j++) {
            let pyStep = (ly + 1) % 2 === 0 ? size / 2 : 0;
            let item = Math.random() > 0.7 && renderData.pop();
            if (item) {
              cellHtml.push(`<div class="item" id="m${ly}-${i}-${j}" onclick="move(this)"
                    style="width:${size}px;height:${size}px;left:${
                size * j + pyStep
              }px;top:${size * i + pyStep}px;
                    background-color:${item.color};text-align:center">${
                item.name
              }</div>`);
            }
          }
        }
      }
      const main = document.querySelector(".main");
      const moveList = document.querySelector(".move_list");
      main.innerHTML = cellHtml.reverse().join("");
      main.style.height = `${size * rows + size * 2}px`;
      main.style.width = `${size * cols}px`;
      moveList.style.height = `${size}px`;
      moveList.style.width = `${size * 7}px`;
      //   第二步：计算出被遮住的底牌，并且标注暗色
      const checkDisabled = () => {
        main.querySelectorAll(".item").forEach((v, i) => {
          const arr = v.id
            .substring(1)
            .split("-")
            .map((v) => Number(v));
          const isPy = (arr[0] + 1) % 2 === 0;
          for (let i = arr[0] + 1; i <= layerCount - 1; i++) {
            const isPyB = (i + 1) % 2 === 0;
            if (isPy === isPyB) {
              const el = main.querySelector(`#m${i}-${arr[1]}-${arr[2]}`);
              if (el) {
                v.classList.add("disabled");
                break;
              }
            } else if (isPy && !isPyB) {
              const result = [
                `${i}-${arr[1]}-${arr[2]}`,
                `${i}-${arr[1]}-${arr[2] + 1}`,
                `${i}-${arr[1] + 1}-${arr[2]}`,
                `${i}-${arr[1] + 1}-${arr[2] + 1}`,
              ].every((k) => {
                return !main.querySelector("#m" + k);
              });
              if (!result) {
                v.classList.add("disabled");
                break;
              } else {
                v.classList.remove("disabled");
              }
            } else if (!isPy && isPyB) {
              const result = [
                `${i}-${arr[1]}-${arr[2]}`,
                `${i}-${arr[1]}-${arr[2] - 1}`,
                `${i}-${arr[1] - 1}-${arr[2]}`,
                `${i}-${arr[1] - 1}-${arr[2] - 1}`,
              ].every((k) => {
                return !main.querySelector("#m" + k);
              });
              if (!result) {
                v.classList.add("disabled");
                break;
              } else {
                v.classList.remove("disabled");
              }
            }
          }
        });
      };
      //   第三步：点击卡片进行清除计算
      let canMove = true;
      const move = (me) => {
        let left = moveList.offsetLeft;
        let top = moveList.offsetTop;
        if (!canMove || me.className.indexOf("disabled") >= 0) {
          return;
        }
        if (moveList.children.length > 0) {
          let el = moveList.lastElementChild;
          left = el.offsetLeft + size;
        }
        canMove = false;
        me.style.top = `${top}px`;
        me.style.left = `${left}px`;
        me.transitionNamesCount = 0;
        me.ontransitionend = (e) => {
          me.transitionNamesCount++;
          if (me.transitionNamesCount === 2) {
            moveEnd(me);
            canMove = true;
          }
        };
      };
      const moveEnd = (me) => {
        me.ontransitionend = null;
        me.setAttribute("onclick", "");
        moveList.appendChild(me);
        const findResult = [...moveList.children].filter(
          (v) => v.innerHTML === me.innerHTML
        );
        if (findResult.length === 3) {
          findResult.forEach((v) => {
            v.ontransitionend = () => {
              moveList.removeChild(v);
              [...moveList.children].forEach((v, i) => {
                v.style.left = `${i * size + moveList.offsetLeft}px`;
              });
              if (moveList.children.length === 7) {
                alert("游戏结束");
                return location.reload();
              } else if (main.children.length === 0) {
                alert("恭喜通关");
                return location.reload();
              }
            };
            setTimeout(() => (v.style.transform = "scale(0)"));
          });
        }
        checkDisabled();
      };
      checkDisabled();
    </script>
  </body>
</html>